package com.wk.configs;

import com.wk.common.GlobalConsts;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
import org.springframework.messaging.support.MessageHeaderAccessor;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

import java.security.Principal;

@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{


    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/wkwebsocket") //表示注册STOMP协议的节点，并指定映射的URL
                .setAllowedOrigins("*") //解决跨域问题
                .withSockJS(); //指定使用SockJS
    }




    //用来配置消息代理，由于我们是实现推送功能，这里的消息代理是/topic
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        //点对点应配置一个/user消息代理，广播式应配置一个/topic消息代理
        registry.enableSimpleBroker("/topic");  //表示客户端订阅地址的前缀信息，也就是客户端接收服务端消息的地址的前缀信息,多个请用逗号分隔
        registry.setApplicationDestinationPrefixes("/app"); //指服务端接收地址的前缀，意思就是说客户端给服务端发消息的地址的前缀
        registry.setUserDestinationPrefix("/user"); //指定用户频道前缀,默认为user可修改

        //上面两个方法定义的信息其实是相反的，一个定义了客户端接收的地址前缀，一个定义了客户端发送地址的前缀
    }

    /*
    * 1、设置拦截器
    * 2、首次连接时，获取Header信息，利用Header里面的信息进行权限认证
    * 3、通过认证的用户，使用accessor.setUser(user)方法，将登陆信息绑定在该StompHeaderAccessor上，在Controlller方法上可以获取StrompHeaderAccessor相关信息
    * */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {

        registration.interceptors(new ChannelInterceptor() {

            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel)
            {
                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message,StompHeaderAccessor.class);
                //1、判断是否首次连接
                if (StompCommand.CONNECT.equals(accessor.getCommand()))
                {
                    //2、判断用户名和密码（做点对点通信时，此处验证用户一般是和数据库进行校验的）
                    String username = accessor.getNativeHeader("username").get(0);
                    String password = accessor.getNativeHeader("password").get(0);
                    if ("admin".equals(username) && "admin".equals(password))
                    {
                        Principal principal = new Principal() {
                            @Override
                            public String getName() {
                                return username;
                            }
                        };
                        accessor.setUser(principal);
                        return message;
                    }else{
                        return null;
                    }
                }
                //不是首次连接，已经登陆成功
                return message;
            }
        });
    }

}
